from pickle import pack, unpack
from binascii import hexlify, unhexlify
from random import seed, randint

__all__ = ['encrypt', 'decrypt']


seed()
op = 0xffffffff

def xor(a, b):
    a1, a2 = unpack('>LL', a[0:8])
    b1, b2 = unpack('>LL', b[0:8])
    r = pack('>LL', (a1^b1)&op, (a2^b2)&op)
    return r
    
def code(v, k):
    n = 16
    delta = 0x9e3779b9
    k = unpack(">LLLL", k[0:16])
    y, z = unpack('>LL', v[0:8])
    s = 0
    for i in range(n):
        s += delta
        y += (op &(z<<4))+ k[0] ^ z+ s ^ (op&(z>>5)) + k[1]
        y &= op
        z += (op &(y<<4))+ k[2] ^ y+ s ^ (op&(y>>5)) + k[3]
        z &= op
    r = pack('>LL', y, z)
    return r

def encrypt(v, k):
    END_CHAR = b'\0'
    FILL_N_OR = 0xF8
    vl = len(v)
    filln = (8-(vl+2))%8 + 2;
    fills = b''
    for i in range(filln):
        fills = fills + bytes([5])
    v = ( bytes([(filln -2)|FILL_N_OR])
          + fills
          + v
          + END_CHAR * 7)
    tr = b'\0'*8
    to = b'\0'*8
    r = b''
    o = b'\0' * 8
    for i in range(0, len(v), 8):
        o = xor(v[i:i+8], tr)
        tr = xor( code(o, k), to)
        to = o
        r += tr
    return r
def decrypt(v, k):
    l = len(v)
    #if l%8 !=0 or l<16:
    #    return ''
    prePlain = decipher(v, k)
    pos = (prePlain[0] & 0x07) +2
    r = prePlain
    preCrypt = v[0:8]
    for i in range(8, l, 8):
        x = xor(decipher(xor(v[i:i+8], prePlain),k ), preCrypt)
        prePlain = xor(x, preCrypt)
        preCrypt = v[i:i+8]
        r += x
    if r[-7:] != b'\0'*7: return None
    

    return r[pos+1:-7]
def decipher(v, k):
    n = 16
    y, z = unpack('>LL', v[0:8])
    a, b, c, d = unpack('>LLLL', k[0:16])
    delta = 0x9E3779B9;
    s = (delta << 4)&op
    for i in range(n):
        z -= ((y<<4)+c) ^ (y+s) ^ ((y>>5) + d)
        z &= op
        y -= ((z<<4)+a) ^ (z+s) ^ ((z>>5) + b)
        y &= op
        s -= delta
        s &= op
    return pack('>LL', y, z)
    
def _test():
    msg = "13669085321"
    key = b"\x39\x55\x37\x9b\x55\x24\xb4\x3b\x75\x05\x8c\x84\x62\x26\xb4\xad"
    cod = encrypt(b"hello,world",key)
    print(hexlify(cod))
    print(decrypt(cod,key))
    print(hexlify(xor(b"abcdefgh",b"hgfedcba")))
    a=pack(">LL",128,190)
    print(hexlify(code(a, key)))
    print(hexlify(decipher(a, key)))
    
if __name__ == "__main__":
    _test()    
    
